package com.example.utils.weixin;

import com.alibaba.fastjson.JSONObject;
import com.example.pojo.RespInfo;
import com.example.pojo.ResultMsg;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @author Zhaoluowei
 * @version 1.0
 * @date 2019/1/21 17:03
 */
@Slf4j
public class WeiXinPay {

    //支付的方法
    public static RespInfo callWeiXinPay(String orderNo, String resultMoney, String openId, String ip, String orderId, String callBackUrl) throws Exception {
        RespInfo respInfo = new RespInfo();
        //获取支付时的ip地址
        log.info("ip地址 " + ip);

        // 拼接订单参数Configure.weixin_pay_callback_url
        SortedMap<String, Object> map = ClientUtils.getMap(new String("ShopPay".getBytes("UTF-8")),
                orderNo, resultMoney, openId, ip, callBackUrl);
        log.info("\n" + " 参数 map   " + map);

        String paramStr = ClientUtils.formatUrlMap(map, false, false);
        log.info("\n" + " 拼接请求参数 paramStr   " + paramStr);//为了拿加签时候的

        String sign = MD5.MD5Encode(paramStr + "&key=" + Configure.key, "UTF-8").toUpperCase();
        log.info("\n" + " 第一次签名 sign   " + sign); //32位的

        // 把 下单参数 和 签名作为参数调用下单接口
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String remotePortData = ClientUtils.getRemotePortData(url, ClientUtils.sendParam(map, sign));
        log.info("\n" + " 调用下单接口传入参数   " +  ClientUtils.sendParam(map, sign));
        log.info("\n" + " 调用下单接口响应   " + remotePortData);

        Map<String, String> xmlParse = ClientUtils.doXMLParse(remotePortData);
        log.info("\n" + " 解析下单响应结果  " + xmlParse);


        if (xmlParse != null) {

            if (xmlParse.get("return_code").equals("SUCCESS") && xmlParse.get("result_code").equals("SUCCESS")) {

                log.info("\n" + " 获取prepay_id成功" + xmlParse.get("prepay_id"));
                String prepayId = xmlParse.get("prepay_id");
                String string = xmlParse.get("code_url");
                log.info("\n" + " 二维码  " + string);

                SortedMap<String, Object> paraMap = new TreeMap<String, Object>();

                String timeStamp = String.valueOf(System.currentTimeMillis());
                String nonceStr = RandomStringGenerator.getRandomStringByLength(32);

                log.info("系统时间" + System.currentTimeMillis());

                paraMap.put("appId", Configure.appId);
                paraMap.put("timeStamp", timeStamp);
                paraMap.put("nonceStr", nonceStr);
                paraMap.put("package", "prepay_id=" + prepayId);
                paraMap.put("signType", "MD5");

                String stringA = ClientUtils.formatUrlMap(paraMap, false, false);
                log.info("二次签名 前： " + stringA);

                String signSecond = MD5.MD5Encode(stringA + "&key=" + Configure.key, "UTF-8").toUpperCase();
                log.info("二次签名： " + signSecond);

                if (org.apache.commons.lang3.StringUtils.isNotBlank(sign)) {
                    JSONObject resultJson = new JSONObject();
                    resultJson.put("appId", Configure.appId);
                    resultJson.put("sign", signSecond);
                    resultJson.put("nonceStr", nonceStr);
                    resultJson.put("timeStamp", timeStamp);
                    resultJson.put("package", "prepay_id=" + prepayId);
                    resultJson.put("orderId", orderId);
                    log.info(" 传前台  " + resultJson);
                    // 返回支付信息
                    respInfo.setCode(0).setMessage("success").setData(resultJson);
                }
            } else {
                // 获取prepay_id失败
                log.info("\n" + xmlParse.get("err_code_des"));
                throw new RuntimeException(xmlParse.get("err_code_des"));
            }
        } else {
            // 获取prepay_id失败
            log.info("\n" + "获取prepay_id失败");
            throw new RuntimeException("获取prepay_id失败");
        }

        return respInfo;
    }


    //===================================== 微信支付订单查询 =============================================//

    public static RespInfo weiXinPayOrderQuery(String orderNo) {
        RespInfo respInfo = new RespInfo();


        //封装请求参数
        SortedMap<String, Object> packageParams = new TreeMap<String, Object>();
        packageParams.put("appid", Configure.appId);// 微信平台应用id
        packageParams.put("mch_id", Configure.mch_id);// 商户号
        packageParams.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));// 随机字符串
        packageParams.put("out_trade_no", orderNo); // 商户订单号

        //微信订单查询地址
        String requestUrl = "https://api.mch.weixin.qq.com/pay/orderquery";

        //加签
        String sign = Signature.createSign("UTF-8", packageParams);
        packageParams.put("sign", sign);

        //封装请求参数 xml格式  生成XML字符串
        String requestXML = ClientUtils.getRequestXml(packageParams);
        log.info("生成的XML字符串requestXML:" + requestXML);
        try {
            // 请求微信服务器方法，拿到微信返回的XML信息
            String result = ClientUtils.getRemotePortData(requestUrl, requestXML);
            log.info("得到微信端返回的XML信息result:" + result);

            // 解析微信返回的XML信息
            Map<String, String> map = ClientUtils.doXMLParse(result);
            log.info("解析XML后的map集合" + map);
            if (map.get("return_code").equals("SUCCESS")) {
                //请求是成功的
                if (map.get("result_code").equals("SUCCESS")) {
                    //业务结果是成功的
                    /**
                     *
                     *
                     * SUCCESS—支付成功
                     * REFUND—转入退款
                     * NOTPAY—未支付
                     * CLOSED—已关闭
                     * REVOKED—已撤销（刷卡支付）
                     * USERPAYING--用户支付中
                     * PAYERROR--支付失败(其他原因，如银行返回失败)
                     */
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("trade_state", map.get("trade_state"));
                    jsonObject.put("map", map);

                    return respInfo.setCode(0).setMessage("业务结果成功").setData(jsonObject);

                } else {
                    //业务结果是失败的
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("err_code", map.get("err_code"));
                    jsonObject.put("err_code_des", map.get("err_code_des"));
                    jsonObject.put("map", map);

                    return respInfo.setCode(1).setMessage("业务结果失败").setData(jsonObject);
                }
            } else {
                //请求失败
                return respInfo.setCode(1).setMessage("请求失败").setData("");
            }
        } catch (Exception e) {
            e.printStackTrace();

            return respInfo.setCode(1).setMessage("查询异常").setData("");
        }
    }

    //===================================== 微信退款订单查询 =============================================//
    public static Map<String, String> weiXinRefundOrderQuery(String orderNo) {
        log.info("微信退款订单查询 --> 进入");
        //封装请求参数
        SortedMap<String, Object> packageParams = new TreeMap<String, Object>();
        packageParams.put("appid", Configure.appId);// 微信平台应用id
        packageParams.put("mch_id", Configure.mch_id);// 商户号
        packageParams.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));// 随机字符串
        packageParams.put("out_trade_no", orderNo); // 商户订单号 --> 这个参数是四选一

        //微信订单查询地址
        String requestUrl = "https://api.mch.weixin.qq.com/pay/refundquery";

        //加签
        String sign = Signature.createSign("UTF-8", packageParams);
        packageParams.put("sign", sign);

        //封装请求参数 xml格式  生成XML字符串
        String requestXML = ClientUtils.getRequestXml(packageParams);
        log.info("生成的XML字符串requestXML:" + requestXML);

        try {
            // 请求微信服务器方法，拿到微信返回的XML信息
            String refundResult = ClientUtils.getRemotePortData(requestUrl, requestXML);
            log.info("得到微信端返回的XML信息result:" + refundResult);

            // 解析微信返回的XML信息
            Map<String, String> map = ClientUtils.doXMLParse(refundResult);
            log.info("解析XML后的map集合" + map);


            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }


        return null;
    }


    //===================================== 微信退款 =============================================//

    /**
     * 微信退款
     *
     * @param tranNo    商户订单号
     * @param refundNo  退款单号
     * @param totalFee  退款金额
     * @param notifyUrl 退款异步回调通知路径
     * @param request   当前请求
     * @return SUCCESS转账成功、REFUNDCLOSE退款关闭、PROCESSING退款处理中、FAIL、退款失败、ERROR程序异常
     * @throws Exception
     */
    public static ResultMsg wxRefund(String tranNo, String refundNo, String totalFee, String refundFee, String notifyUrl, HttpServletRequest request)
            throws Exception {
        SortedMap<String, Object> packageParams = new TreeMap<String, Object>();
        packageParams.put("appid", Configure.appId);// 微信平台应用id
        packageParams.put("mch_id", Configure.mch_id);// 商户号
        packageParams.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));// 随机字符串
        packageParams.put("out_trade_no", tranNo); // 商户订单号
        packageParams.put("out_refund_no", refundNo);// 商户自己生成的退款单号
        packageParams.put("total_fee", totalFee);// 订单金额
        packageParams.put("refund_fee", refundFee);// 退款金额
        packageParams.put("notify_url", notifyUrl);// 退款回调路径
        ResultMsg rm = null;
        try {
            String requestUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            Map<String, String> map = deal(packageParams, requestUrl);
            String code = map.get("return_code");
            String msg = map.get("return_msg");
            if (code.equals("SUCCESS")) {
                String r_code = map.get("result_code");
                if (r_code.equals("SUCCESS")) {
                    // 退款申请接收成功
                    /** 查询退款验证 */
                    //rm = queryRefund(tranNo, request);
                    rm = new ResultMsg("SUCCESS", "请求发送成功");
                    log.info("退款申请接收成功" + map);
                } else {
                    // 退款失败
                    rm = new ResultMsg("FAIL", "错误码：" + map.get("err_code") + " 错误信息：" + map.get("err_code_des"));
                }
            } else {
                // 退款请求失败
                rm = new ResultMsg("FAIL", msg);
            }
        } catch (Exception e) {
            rm = new ResultMsg("ERROR", "程序异常");
            e.printStackTrace();
        }
        log.info("返回结果：" + rm.toString());
        return rm;
    }


    @SuppressWarnings("unchecked")
    public static Map<String, String> deal(
            SortedMap<String, Object> parameterMap, String requestUrl) throws Exception {
        // 加签
        String sign = Signature.createSign("UTF-8", parameterMap);
        parameterMap.put("sign", sign);
        // 生成XML字符串
        String requestXML = ClientUtils.getRequestXml(parameterMap);
        log.info("生成的XML字符串requestXML:" + requestXML);

        // 请求微信服务器方法，拿到微信返回的XML信息
        String result = ClientUtils.httpsRequest2(requestUrl, requestXML);
        log.info("得到微信端返回的XML信息result:" + result);

        // 解析微信返回的XML信息
        Map<String, String> map = ClientUtils.doXMLParse(result);

        log.info("解析XML后的map集合" + map);
        return map;
    }

    /**
     * 账单下载
     *
     * @param billDate 账单日期
     * @return map
     */
//    public static RespInfo downloadBill(String billDate) throws Exception{
//        RespInfo resp;
//        // 需要查询的账单类型（ALL:表示当天所有账单信息;SUCESS:表示当天成功的账单信息;REFUND，返回当日退款订单信息;RECHARGE_REFUND，返回当日充值退款订单信息（相比其他对账单多一栏“返还手续费”））
//        String billType = "ALL";
//        String xmlStr = ClientUtils.WeiXinDownloadBill(billDate, billType);
//        // 微信账单下载请求路径
//        String requestUrl = "https://api.mch.weixin.qq.com/pay/downloadbill";
//        // 微信返回的XML格式的参数
//        String retStr = ClientUtils.getRemotePortData(requestUrl, xmlStr);
//        if(retStr.contains("xml")) {
//            Map<String, String> map = ClientUtils.doXMLParse(retStr);
//            String msg = map.get("return_msg");
//            log.info("错误！账单下载获取失败！返回信息为:" + msg);
//            if ("NO Bill Exist".equals(msg)){
//                resp = new RespInfo(1, "当前商户号没有已成交的订单，不生成对账单");
//            } else if ("Bill Creating".equals(msg)) {
//                resp = new RespInfo(2, "当前商户号没有已成交的订单或对账单尚未生成");
//            } else if ("system error".equals(msg) || "SYSTEMERROR".equals(msg)){
//                resp = new RespInfo(3, "系统超时,请尝试再次查询。");
//            } else {
//                resp = new RespInfo(-1, "下载失败");
//            }
//        } else {
//            // 去空格、换行以及表头
//            String tradeMsg = retStr.replace(" ", "").replaceAll("[\r\n]", "").substring(retStr.indexOf("`")-1);
//            // 去掉汇总数据，并且去掉'`'
//            String tradeInfo = tradeMsg.substring(0, tradeMsg.indexOf("总")).replace("`", "");
//            // 以“%”作为分割
//            String[] tradeArray = tradeInfo.split("%");
//            resp = new RespInfo(0, tradeArray);
//        }
//        return resp;
//    }

}
